home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / lib / C / lispread.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  11.4 KB  |  526 lines

  1. /*
  2.  * lispread.c
  3.  *
  4.  * Herein lies a function to read strings printed by lispDisplay.
  5.  * Additionally, there is a lisp token parser, and a lisp 
  6.  * 
  7.  * the functions are lispRead, lsptok, and LispToken.
  8.  *
  9.  * Bugs:  (nil) won't work.
  10.  *
  11.  * Identification:
  12.  *    $Header: /private/postgres/src/lib/C/RCS/lispread.c,v 1.16 1991/11/19 03:08:25 mer Exp $
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include <ctype.h>
  17.  
  18. #include "tmp/postgres.h"
  19.  
  20. RcsId("$Header: /private/postgres/src/lib/C/RCS/lispread.c,v 1.16 1991/11/19 03:08:25 mer Exp $");
  21.  
  22. #include "parser/atoms.h"
  23. #include "rules/params.h"
  24. #include "utils/palloc.h"
  25. #include "utils/log.h"
  26.  
  27. #include "nodes/nodes.h"
  28. #include "nodes/pg_lisp.h"
  29. #include "nodes/primnodes.h"
  30. #include "nodes/primnodes.a.h"
  31.  
  32. #include "lib/equalfuncs.h"
  33. #include "nodes/pg_lisp.h"
  34. #include "utils/lsyscache.h"
  35. double atof();
  36.  
  37. #define RIGHT_PAREN (1000000 + 1)
  38. #define LEFT_PAREN  (1000000 + 2)
  39. #define PLAN_SYM    (1000000 + 3)
  40.  
  41. /*----------------------------------------------------------
  42.  *
  43.  * Param Node handling.
  44.  *
  45.  * makeParamList is a global variable. If it is set to 'true' then
  46.  * every time a Param node is generated, we add an entry to
  47.  * paramList (another global variable).
  48.  * maxParamListEntries is the current maximum number of
  49.  * entries the array can handle.
  50.  */
  51.  
  52. static bool makeParamList;
  53. static ParamListInfo paramList;
  54. static int maxParamListEntries;
  55.  
  56. static
  57. void
  58. addToParamList();
  59.  
  60. /*-------------------------------------------------------------
  61.  * LispToken returns the type of the lisp token contained in token.
  62.  * It returns one of
  63.  * 
  64.  * PGLISP_ATOM
  65.  * PGLISP_DTPR
  66.  * PGLISP_FLOAT
  67.  * PGLISP_INT
  68.  * PGLISP_STR
  69.  * PGLISP_VECI
  70.  *
  71.  * and some of its own:
  72.  *
  73.  * RIGHT_PAREN
  74.  * LEFT_PAREN
  75.  * PLAN_SYM
  76.  * DOTPLAN_SYM
  77.  * 
  78.  * LispToken will check only the
  79.  * first character for many lisp objects, such as strings or vectors.
  80.  *
  81.  * Does no error checking as it assumes the file is electronically
  82.  * generated.
  83.  */
  84.  
  85. NodeTag lispTokenType(token, length)
  86.  
  87. char *token;
  88. int length;
  89.  
  90. {
  91.     NodeTag retval;
  92.     int sign;
  93.  
  94.     /*
  95.      * Check if the token is a number (decimal or integer,
  96.      * positive or negative
  97.      */
  98.     if (isdigit(*token) ||
  99.        (length>=2 && *token=='-' && isdigit(*(token+1)) ))
  100.     {
  101.         /*
  102.          * skip the optional '-' (i.e. negative number)
  103.          */
  104.         if (*token == '-') {
  105.             token++;
  106.         }
  107.  
  108.         /*
  109.          * See if there is a decimal point
  110.          */
  111.  
  112.         for (; length && *token != '.'; token++, length--);
  113.         
  114.         /*
  115.          * if there isn't, token's an int, otherwise it's a float.
  116.          */
  117.  
  118.         retval = (*token != '.') ? PGLISP_INT : PGLISP_FLOAT;
  119.     }
  120.     else if (isalpha(*token))
  121.         retval = PGLISP_ATOM;
  122.     else if (*token == '(')
  123.         retval = LEFT_PAREN;
  124.     else if (*token == ')')
  125.         retval = RIGHT_PAREN;
  126.     else if (*token == '\"')
  127.         retval = PGLISP_STR;
  128.     else if (*token == '.' && length == 1)
  129.         retval = PGLISP_DTPR;
  130.     else if (*token == '#' && token[1] == 'S' && length == 2)
  131.         retval = PLAN_SYM;
  132.     else if (*token == '#' 
  133.               && token[1] == '<'
  134.               && isdigit(token[2])
  135.           && length < 2)
  136.         retval = PGLISP_VECI;
  137.     return(retval);
  138. }
  139.  
  140. /*
  141.  * This guy does all the reading.
  142.  *
  143.  * Secrets:  He assumes that lsptok already has the string (see below).
  144.  * Any callers should set read_car_only to true.
  145.  */
  146.  
  147. LispValue
  148. lispRead(read_car_only)
  149.  
  150. bool read_car_only;
  151.  
  152. {
  153.     char *token, *lsptok();
  154.     NodeTag type, lispTokenType();
  155.     LispValue this_value, return_value, parsePlanString();
  156.     int tok_len;
  157.     int i, nbytes;
  158.     char tmp;
  159.     bool make_dotted_pair_cell = false;
  160.  
  161.     token = lsptok(NULL, &tok_len);
  162.  
  163.     if (token == NULL) return(NULL);
  164.  
  165.     type = lispTokenType(token, tok_len);
  166.  
  167.     
  168.     switch(type)
  169.     {
  170.         case PLAN_SYM:
  171.             token = lsptok(NULL, &tok_len);
  172.             if (token[0] != '(') return(NULL);
  173.             this_value = parsePlanString(NULL);
  174.             token = lsptok(NULL, &tok_len);
  175.             if (token[0] != ')') return(NULL);
  176.             if (makeParamList) {
  177.                 if (IsA(this_value,Param)) {
  178.                 addToParamList(this_value);
  179.                 }
  180.             }
  181.             if (!read_car_only)
  182.                 make_dotted_pair_cell = true;
  183.             else
  184.                 make_dotted_pair_cell = false;
  185.             break;
  186.         case LEFT_PAREN:
  187.             if (!read_car_only)
  188.             {
  189.                 this_value = lispDottedPair();
  190.                 this_value->val.car = lispRead(false);
  191.                 this_value->cdr = lispRead(false);
  192.                 if (this_value->cdr == (LispValue) -1)
  193.                 {
  194.                     this_value->cdr = CAR(lispRead(false));
  195.                 }
  196.             }
  197.             else
  198.             {
  199.                 this_value = lispRead(false);
  200.             }
  201.             break;
  202.         case RIGHT_PAREN:
  203.             this_value = LispNil;
  204.             break;
  205.         case PGLISP_ATOM:
  206.             if (!strncmp(token, "nil", 3))
  207.             {
  208.                 this_value = LispNil;
  209.                 /*
  210.                  * It might be "nil" but it is an atom!
  211.                  */
  212.                 if (read_car_only) {
  213.                     make_dotted_pair_cell = false;
  214.                 } else {
  215.                     make_dotted_pair_cell = true;
  216.                 }
  217.             }
  218.             else
  219.             {
  220.  
  221.                 tmp = token[tok_len];
  222.                 token[tok_len] = '\0';
  223.                 this_value = lispAtom(token);
  224.                 token[tok_len] = tmp;
  225.                 make_dotted_pair_cell = true;
  226.             }
  227.             break;
  228.         case PGLISP_FLOAT:
  229.             tmp = token[tok_len];
  230.             token[tok_len] = '\0';
  231.             this_value = lispFloat(atof(token));
  232.             token[tok_len] = tmp;
  233.             make_dotted_pair_cell = true;
  234.             break;
  235.         case PGLISP_INT:
  236.             tmp = token[tok_len];
  237.             token[tok_len] = '\0';
  238.             this_value = lispInteger(atoi(token));
  239.             token[tok_len] = tmp;
  240.             make_dotted_pair_cell = true;
  241.             break;
  242.         case PGLISP_STR:
  243.             tmp = token[tok_len - 1];
  244.             token[tok_len - 1] = '\0';
  245.             token++;
  246.             this_value = lispString(token);
  247.             token[tok_len - 2] = tmp;
  248.             make_dotted_pair_cell = true;
  249.             break;
  250.         case PGLISP_VECI:
  251.             sscanf(token, "#<%d:", &nbytes);
  252.             this_value = lispVectori(nbytes);
  253.             for (i = 0; i < nbytes; i++)
  254.             {
  255.                 token = lsptok(NULL, tok_len);
  256.                 this_value->val.veci->data[i] = atoi(token);
  257.             }
  258.             token = lsptok(NULL, tok_len); /* get > */
  259.             make_dotted_pair_cell = true;
  260.             break;
  261.         case PGLISP_DTPR:
  262.             this_value = (LispValue) -1;
  263.             break;
  264.         default:
  265.             elog(WARN, "Bad type (lispRead)");
  266.             break;
  267.     }
  268.     if (make_dotted_pair_cell)
  269.     {
  270.         return_value = lispDottedPair();
  271.         return_value->val.car = this_value;
  272.         if (!read_car_only)
  273.         {
  274.             return_value->cdr = lispRead(false);
  275.             if (return_value->cdr == (LispValue) -1)
  276.             {
  277.                 return_value->cdr = lispRead(false);
  278.             }
  279.         }
  280.         else
  281.         {
  282.             return_value->cdr = LispNil;
  283.         }
  284.     }
  285.     else
  286.     {
  287.         return_value = this_value;
  288.     }
  289.     return(return_value);
  290. } /* lispRead */
  291.  
  292. /*
  293.  * Works kinda like strtok, except it doesn't put nulls into string.
  294.  * 
  295.  * Returns the length in length instead.  The string can be set without
  296.  * returning a token by calling lsptok with length == NULL.
  297.  *
  298.  */
  299.  
  300. char *lsptok(string, length)
  301.  
  302. char *string;
  303. int  *length;
  304.  
  305. {
  306.     static char *local_str;
  307.     char *ret_string;
  308.     
  309.  
  310.     if (string != NULL) 
  311.     {
  312.         local_str = string;
  313.         if (length == NULL) {
  314.             return(NULL);
  315.         }
  316.     }
  317.  
  318.  
  319.     for (; *local_str == ' '
  320.         || *local_str == '\n'
  321.         || *local_str == '\t'; local_str++);
  322.  
  323.     /*
  324.      * Now pointing at next token.
  325.      */
  326.  
  327.     ret_string = local_str;
  328.     if (*local_str == '\0') return(NULL);
  329.     *length = 1;
  330.  
  331.     if (*local_str == '\"')
  332.     {
  333.         for (local_str++; *local_str != '\"'; (*length)++, local_str++);
  334.         (*length)++; local_str++;
  335.     }
  336.     else if (*local_str == ')' || *local_str == '(')
  337.     {
  338.         local_str++;
  339.     }
  340.     else
  341.     {
  342.         for (; *local_str != ' '
  343.             && *local_str != '\n'
  344.             && *local_str != '\t'
  345.             && *local_str != '('
  346.             && *local_str != ')'; local_str++, (*length)++);
  347.         (*length)--;
  348.     }
  349.     return(ret_string);
  350. }
  351.  
  352. /*---------------------------------------------------------------------
  353.  * This function fronts the more generic lispRead function by calling
  354.  * lsptok with length == NULL, which just passes lsptok the string.
  355.  *
  356.  * There are two version of lispReadString.
  357.  *
  358.  *      lispReadString (the simple one)
  359.  *           and
  360.  *      lispReadStringWithParams
  361.  *
  362.  * the second one takes en extra (output) argument, 'thisParamListP'
  363.  * If it is non NULL then when the routine returns it will point to
  364.  * a 'ParamLispInfo' which contains information about all the Param
  365.  * nodes of the LispValue returned.
  366.  *
  367.  */
  368.  
  369. LispValue
  370. lispReadStringWithParams(string, thisParamListP)
  371.  
  372. char *string;
  373. ParamListInfo *thisParamListP;
  374.  
  375. {
  376.     LispValue res;
  377.  
  378.     if (thisParamListP == NULL) {
  379.         makeParamList = false;    /* global variable */
  380.     }
  381.     else {
  382.         makeParamList = true;    /* global variable */
  383.         paramList = NULL;        /* global variable */
  384.     }
  385.  
  386.     (void) lsptok(string, NULL);
  387.     res = lispRead(true);
  388.  
  389.     if (thisParamListP != NULL) {
  390.         *thisParamListP = paramList;
  391.     }
  392.     return(res);
  393. }
  394.                 
  395. LispValue
  396. lispReadString(string)
  397. char *string;
  398. {
  399.     LispValue res;
  400.  
  401.     res = lispReadStringWithParams(string, NULL);
  402.     return(res);
  403. }
  404.  
  405. /*-----------------------------------------------------------
  406.  *
  407.  * addToParamList
  408.  *
  409.  * Add an entry for the given Param node to array
  410.  * 'paramList' (thsi is a global variable).
  411.  *
  412.  * 'paramList' points to a place in memory where 'ParamListInfoData'
  413.  * structs are contiguously stored. A struct with its field 'kind'
  414.  * equal to PARAM_INVALID is always the last entry.
  415.  */
  416.  
  417. static
  418. void
  419. addToParamList(paramNode)
  420. Param paramNode;
  421. {
  422.     int size;
  423.     int oldSize;
  424.     int i;
  425.     int delta = 10;
  426.     ParamListInfo temp;
  427.  
  428.     if (paramList == NULL) {
  429.     /*
  430.      * this is the first entry.
  431.      * allocate some space for a few entries...
  432.      */
  433.     maxParamListEntries = delta;
  434.     size = sizeof(ParamListInfoData) * maxParamListEntries;
  435.     paramList = (ParamListInfo) palloc(size);
  436.     Assert(PointerIsValid(paramList));
  437.     paramList[0].kind = PARAM_INVALID;
  438.     elog(DEBUG,"added initial entry");
  439.     }
  440.  
  441.     /*
  442.      * search the array until either another entry with
  443.      * the same name  and paramkind is found
  444.      * or till we reach the end of the array.
  445.      */
  446.     i = 0;
  447.     while(paramList[i].kind != PARAM_INVALID) {
  448.     int match = false;
  449.     if (paramList[i].kind != get_paramkind(paramNode))
  450.     {
  451.         i++;
  452.         continue;
  453.     }
  454.     switch (paramList[i].kind) {
  455.     case PARAM_NUM:
  456.         match = (paramList[i].id == get_paramid(paramNode));
  457.         break;
  458.     case PARAM_NEW:    
  459.     case PARAM_OLD: {
  460.         match = NameIsEqual(paramList[i].name, get_paramname(paramNode));
  461.         if (match && (paramList[i].id != get_paramid(paramNode))) {
  462.         elog(WARN, "param node: same name, different id");
  463.         }
  464.         break;
  465.     }
  466.     case PARAM_NAMED:
  467.     default: elog(WARN, "unexpected kind of parameter node");
  468.         break;
  469.     }
  470.     if (match) break;
  471.     i+=1;
  472.     }
  473. /*        if ((PARAM_NUM != get_paramkind(paramNode)) &&
  474.         !NameIsEqual(paramList[i].name, get_paramname(paramNode))
  475.         && paramList[i].kind == get_paramkind(paramNode))
  476.         */
  477.  
  478.  
  479.     if (paramList[i].kind != PARAM_INVALID) {
  480.     /*
  481.      * we have found a duplicate entry
  482.      */
  483.     return;
  484.     }
  485.  
  486.     /*
  487.      * No entry exists for this parameter, therefore we must add
  488.      * a  new entry at the end of the array.
  489.      * We must first check to see if the array is big enough
  490.      * to hold this new entry. If not, then we have to reallocate
  491.      * some space.
  492.      */
  493.  
  494.     if ((i+1) >= maxParamListEntries) {
  495.     oldSize = sizeof(ParamListInfoData) * maxParamListEntries;
  496.     maxParamListEntries += delta;
  497.     size = sizeof(ParamListInfoData) * maxParamListEntries;
  498.     temp = (ParamListInfo) palloc(size);
  499.     Assert(PointerIsValid(temp));
  500.     /*
  501.      * copy the entries of the old array to the new one
  502.      */
  503.     bcopy((char *)paramList, (char *)temp, (unsigned int) oldSize);
  504.     pfree((Pointer)paramList);
  505.     paramList = temp;
  506.     }
  507.  
  508.     /*
  509.      * Ok, there is enough room for a new entry.
  510.      */
  511.     paramList[i].kind = get_paramkind(paramNode);
  512.     paramList[i].name = get_paramname(paramNode); /* Note: no copy! */
  513.     paramList[i].id = get_paramid(paramNode);
  514.     paramList[i].type = get_paramtype(paramNode);
  515.     paramList[i].length = (Size) get_typlen(get_paramtype(paramNode));
  516.     paramList[i].byval = get_typbyval(get_paramtype(paramNode));
  517.  
  518.     /*
  519.      * mark the next entry in paramList as invalid...
  520.      */
  521.     paramList[i+1].kind = PARAM_INVALID;
  522.  
  523. }
  524.  
  525.  
  526.